-
Notifications
You must be signed in to change notification settings - Fork 5k
Initialize MSAL before use to fix auth regression #2685
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initialize MSAL before use to fix auth regression #2685
Conversation
…async init (fixes uninitialized_public_client_application); show small loading state
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes an MSAL authentication regression that occurred after upgrading to MSAL 4.x, where calling MSAL APIs before initialization caused "uninitialized_public_client_application" errors. The fix ensures proper MSAL initialization with error handling and provides a loading state during initialization.
- Creates a stable PublicClientApplication instance using useMemo to prevent re-initialization
- Adds proper async initialization with await on initialize() before using MSAL APIs
- Implements error handling, console logging, and a loading placeholder during initialization
app/frontend/src/layoutWrapper.tsx
Outdated
if (useLogin) { | ||
var msalInstance = new PublicClientApplication(msalConfig); | ||
// Create a stable MSAL instance (avoid re-init/duplicate listeners; single shared client for MsalProvider). | ||
const msalInstance = useMemo(() => new PublicClientApplication(msalConfig), []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cline's suggested fix did not use useMemo, but Copilot+GPT5 thought it was a good idea, to avoid re-construction across renders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs show this general type of pattern for accomplishing that (without useMemo()), but useMemo() should achieve the goal of ensuring it's only created once. I don't know enough about the app to understand the overall flow and how often the component is rerendered. But, assuming it is, useMemo should help there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an SPA - my understanding is that this wrapper holds all the content displayed and shouldn't be re-rendered unless the page is refreshed
const msalInstance = useMemo(() => new PublicClientApplication(msalConfig), []); | ||
const [initialized, setInitialized] = useState(false); | ||
// Track mount state so we don't call setState after unmount if async init resolves late | ||
const mounted = useRef<boolean>(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new mounted ref is to avoid setState calls inside the async init() below if the component unmounts during all that. Don't know how common that is.
…alize() gated with try/finally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Recommend switching to singleton pattern to make it easier
https://learn.microsoft.com/en-us/entra/msal/javascript/react/getting-started#initialization
Combined with something like this
// main bootstrap (index.tsx or similar)
import { createRoot } from "react-dom/client";
import { MsalProvider } from "@azure/msal-react";
import { msalInstance } from "./auth/msal";
import App from "./App";
(async () => {
await msalInstance.initialize(); // ensures MSAL is ready before any API use
createRoot(document.getElementById("root")!).render(
);
})();
@DanWahlin @mattgotteiner I've revised the PR to use an approach closer to the documentation, with the MsalProvider moved into index.tsx, and then Layout uses useMsal. |
I like that approach better. Eliminates any rerenders which would get rid of the singleton challenge. |
Purpose
Fix MSAL auth regression after the MSAL 4.x upgrade that caused "uninitialized_public_client_application" when MSAL APIs were called before initialization. This change:
Fixes #2675.
Does this introduce a breaking change?
When developers merge from main and run the server, azd up, or azd deploy, will this produce an error?
If you're not sure, try it out on an old environment.
Does this require changes to learn.microsoft.com docs?
This repository is referenced by this tutorial
which includes deployment, settings and usage instructions. If text or screenshot need to change in the tutorial,
check the box below and notify the tutorial author. A Microsoft employee can do this for you if you're an external contributor.
Type of change
Code quality checklist
See CONTRIBUTING.md for more details.
python -m pytest
).python -m pytest --cov
to verify 100% coverage of added linespython -m mypy
to check for type errorsruff
andblack
manually on my code.